[アップデート] Amazon CloudFront と Lambda 関数 URL オリジンの OAC の設定が AWS CDK で簡単に実装可能になりました

[アップデート] Amazon CloudFront と Lambda 関数 URL オリジンの OAC の設定が AWS CDK で簡単に実装可能になりました

Clock Icon2024.11.25

こんにちは、製造ビジネステクノロジー部の若槻です。

AWS CDK の最近のリリースである v2.168.0 で、下記の機能アップデートが追加されていました。

cloudfront: function URL origin access control L2 construct (#31339) (b8f47c8), closes #31629

今年 2024 年 4 月に、Amazon CloudFront が Lambda 関数 URL オリジンに対して Origin Access Control (OAC) をサポートするようになりました。これにより指定の CloudFront Distribution からのみ のアクセスを許可し、Lambda 関数 URL オリジンを保護することが可能となりました。
https://aws.amazon.com/about-aws/whats-new/2024/04/amazon-cloudfront-oac-lambda-function-url-origins/

今回の AWS CDK のアップデートにより、この CloudFront と Lambda 関数 URL の OAC を CDK の L2 Construct で簡単に設定できるようになりました。

試してみた

CDK パッケージのアップデート

AWS CDK モジュールを v2.168.0 以上にアップデートします。

npm i aws-cdk-lib@latest aws-cdk@latest

CDK 実装

AWS CDK で CloudFront と Lambda 関数 URL の OAC を設定する実装です。FunctionUrlOrigin クラスの withOriginAccessControl メソッドを使用して CloudFront Distribution のオリジンに Lambda 関数 URL を指定することにより、OAC での保護も合わせて設定できます。

lib/main-stack.ts
import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';
import * as lambda from 'aws-cdk-lib/aws-lambda';
import * as lambda_nodejs from 'aws-cdk-lib/aws-lambda-nodejs';
import * as cloudfront from 'aws-cdk-lib/aws-cloudfront';
import * as origins from 'aws-cdk-lib/aws-cloudfront-origins';

export class MainStack extends cdk.Stack {
  constructor(scope: Construct, id: string) {
    super(scope, id);

    const myFunction = new lambda_nodejs.NodejsFunction(this, 'MyFunction');

    const myFunctionUrl = myFunction.addFunctionUrl({
      authType: lambda.FunctionUrlAuthType.AWS_IAM, // 認証タイプとして AWS_IAM を指定し、OAC で保護可能とする
    });

    new cloudfront.Distribution(this, 'MyDistribution', {
      defaultBehavior: {
        origin:
          // @see https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_cloudfront.FunctionUrlOriginAccessControl.html
          origins.FunctionUrlOrigin.withOriginAccessControl(myFunctionUrl),
      },
    });
  }
}

参考までに、OAC で保護せずに Lambda 関数 URL を指定する場合のコードも折りたたみで記載しておきます。

OAC で保護しない場合
lib/main-stack.ts
import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';
import * as lambda from 'aws-cdk-lib/aws-lambda';
import * as lambda_nodejs from 'aws-cdk-lib/aws-lambda-nodejs';
import * as cloudfront from 'aws-cdk-lib/aws-cloudfront';
import * as origins from 'aws-cdk-lib/aws-cloudfront-origins';

export class MainStack extends cdk.Stack {
  constructor(scope: Construct, id: string) {
    super(scope, id);

    const myFunction = new lambda_nodejs.NodejsFunction(this, 'MyFunction');

    const myFunctionUrl = myFunction.addFunctionUrl({
      authType: lambda.FunctionUrlAuthType.AWS_IAM,
    });

    new cloudfront.Distribution(this, 'MyDistribution', {
      defaultBehavior: {
        origin: new origins.FunctionUrlOrigin(myFunctionUrl), // OAC で保護しない場合
      },
    });
  }
}

Lambda 関数のコードは以下のようになります。

lib/main-stack.MyFunction.ts
export const handler = async (event: any): Promise<any> => {
  // リクエスト情報を使用してレスポンスを返す
  const response = {
    statusCode: 200,
    headers: {
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      message: 'Hello from Lambda!',
      request: event,
    }),
  };

  return response;
};

上記の実装を CDK によりデプロイすると、オリジンに Lambda 関数 URL が指定され、オリジンの保護に OAC が使用されていることが確認できました。

動作確認

作成された CloudFront Distribution の URL にアクセスすると、Lambda 関数 URL からレスポンスを取得できました。OAC によるオリジンのアクセスでは 856369053181 という AWS マネージドアカウントが使用されているようです。

curl https://d15lafwe30yr9y.cloudfront.net/ | jq .
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  2434  100  2434    0     0  45144      0 --:--:-- --:--:-- --:--:-- 45074
{
  "message": "Hello from Lambda!",
  "request": {
    "version": "2.0",
    "routeKey": "$default",
    "rawPath": "/",
    "rawQueryString": "",
    "headers": {
      "x-amz-content-sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
      "x-amzn-tls-version": "TLSv1.2",
      "x-amz-date": "20241125T120801Z",
      "x-forwarded-proto": "https",
      "x-amz-source-account": "XXXXXXXXXXXX",
      "x-forwarded-port": "443",
      "x-forwarded-for": "XXX.XXX.XXX.XXX",
      "x-amz-security-token": "IQoJb3JpZ...",
      "via": "2.0 6a4098eaf995c1e965d6434534971664.cloudfront.net (CloudFront)",
      "x-amz-source-arn": "arn:aws:cloudfront::XXXXXXXXXXXX:distribution/E19HGLBL0VS740",
      "x-amzn-tls-cipher-suite": "ECDHE-RSA-AES128-GCM-SHA256",
      "x-amzn-trace-id": "Root=1-674468a1-2b9a07f44a81e2e8430ef07d",
      "host": "znlxyvy3yhvmdbxhjt4forfmca0cylol.lambda-url.ap-northeast-1.on.aws",
      "x-amz-cf-id": "rAQGmEaAmDX3GH9Y-kPFsG2Vat_rMKIH0EQzKLmps4EhMJX6nmsVbg==",
      "user-agent": "Amazon CloudFront"
    },
    "requestContext": {
      "accountId": "856369053181",
      "apiId": "znlxyvy3yhvmdbxhjt4forfmca0cylol",
      "authorizer": {
        "iam": {
          "accessKey": "ASIXXXXXXXXXXXXXXXXX",
          "accountId": "856369053181",
          "callerId": "AROA4OY4SXX6VEIZRJRCJ:OriginAccessSession",
          "cognitoIdentity": null,
          "principalOrgId": null,
          "userArn": "arn:aws:sts::856369053181:assumed-role/OriginAccessControlRole/OriginAccessSession",
          "userId": "AROA4OY4SXX6VEIZRJRCJ:OriginAccessSession"
        }
      },
      "domainName": "znlxyvy3yhvmdbxhjt4forfmca0cylol.lambda-url.ap-northeast-1.on.aws",
      "domainPrefix": "znlxyvy3yhvmdbxhjt4forfmca0cylol",
      "http": {
        "method": "GET",
        "path": "/",
        "protocol": "HTTP/1.1",
        "sourceIp": "64.252.113.135",
        "userAgent": "Amazon CloudFront"
      },
      "requestId": "d280dbea-fe7e-40e8-a43a-fd9fbf021b78",
      "routeKey": "$default",
      "stage": "$default",
      "time": "25/Nov/2024:12:08:01 +0000",
      "timeEpoch": 1732536481736
    },
    "isBase64Encoded": false
  }
}

Lambda 関数 URL に直接アクセスすると、ブラウザの場合は 403 Forbidden が返されました。

curl でアクセスすると、こちらはレスポンスが返ってきませんでした。OAC による保護もちゃんと働いているようです。

curl znlxyvy3yhvmdbxhjt4forfmca0cylol.lambda-url.ap-northeast-1.on.aws

参考

https://docs.aws.amazon.com/ja_jp/AmazonCloudFront/latest/DeveloperGuide/troubleshooting-distributions.html

注意点

Lambda 関数 URL の返却内容を更新して CDK デプロイをしても、CloudFront Distribution からアクセス時のレスポンスが更新されませんでした。その場合は、CloudFront Distribution のキャッシュが原因である可能性があります。

よって Distribution のパスに対してバリデーションを行うことにより、更新後の Lambda 関数のレスポンスを取得可能となりました。

aws_s3_deployment Construct クラスのように CDK デプロイ時にデフォルトでバリデーションが行われる挙動とならない点には注意しましょう。

おわりに

Amazon CloudFront と Lambda 関数 URL オリジンの OAC の設定が AWS CDK で簡単に実装可能になったので、共有しました。

生成 AI による処理を行う API を公開する場合に CloudFront と Lambda 関数 URL の組み合わせを採用するケースがチラホラ見られます。そのような構成で OAC による保護が CDK で簡単に設定できるのはなかなか嬉しいのではないでしょうか。

以上

Share this article

facebook logohatena logotwitter logo

© Classmethod, Inc. All rights reserved.